//后来优化后的 compose ——> 迭代递推(first+rest)：分治思想 
// pipeline 迭代器：每次执行第一个，将结果返回(表达式)传递给 next
// 1、类比数学中的递推数列  递推表达式：迭代，分治(必须满足最终的next是有解的：终止条件退出递推) 
// 2、参数分解：满足乘法结合律 
export default function compose(...fns) {
  if (fns.length === 0) {
     return args[0]
  }
 if (fns.length === 1) return fns[0];
 return fns.reduce(
   (a, b) => (...args) => a(b(...args))
 );
}

let add = compose(add3, add2, add1);
let r = add("zfpx");
console.log(r); // zfpx123 


//KOA2
function compose (middleware) {
  if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!');
  for (const fn of middleware) {
    if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!');
  }
 
  /**
   * @param {Object} ctx
   * @return {Promise}
   * @api public
   */
  return function fn (ctx, next) {
    return dispatch(0);
    function dispatch (i) {
      let middlewareFn = middleware[i]
      try {
        return Promise.resolve(middlewareFn(ctx, dispatch.bind(null, i + 1)));
      } catch (err) {
        return Promise.reject(err);
      }
    }
  }
}

function use(fn) {
  // 省略部分代码...
  this.middleware.push(fn);
  return this;
}


//Express
const stack = [];
/** 通过 use 注册 */
function use(fn) {
  stack.push(fn);
}
 
/** 请求到达的时候，会触发handle方法。接着next函数从队列中顺序取出并执行 */
function handle(req, res) {
  var idx = 0;
  next();
  function next() {
    var fn = stack[idx++];
    fn(req, res, next)
  }
}


//Axios 没有中间件，但有类似功能的拦截器(interceptors) 
// 本质上都是在数据处理链路的 2 点之间，提供独立的、配置化的、可叠加的额外功能
function Axios(instanceConfig) {
  this.defaults = instanceConfig;
  this.interceptors = {
    request: new InterceptorManager(),
    response: new InterceptorManager()
  };
}
function InterceptorManager() {
  this.handlers = [];
}
InterceptorManager.prototype.use = function use(fulfilled, rejected) {
  this.handlers.push({
    fulfilled: fulfilled,
    rejected: rejected
  });
  return this.handlers.length - 1;
};
/**
 * Axios内部会维护 2 个 interceptors，它们有独立的 handlers 数组。
 * use就是往数组添加元素而已，跟其它框架不同的是这里的数组元素不是一个函数，而是一个对象，
 * 包含fulfilled和rejected 2 个属性。第二个参数不传的时候rejected就是 undefined。
 * 
 * 通过 promise 的链式调用，将 interceptors 串联了起来，
 * 执行顺序是：requestInterceptorChain -> chain -> responseInterceptorChain。
 * 这里有一个默认的约定，chain 里的元素都是按照[fulfilled1, rejected1, fulfilled2, rejected2]这种模式排列的，
 * 所以注册 interceptors 的时候如果没有提供第二个参数，也会有一个默认值 undefined：
 */
 Axios.prototype.request = function request(config) {
  config = mergeConfig(this.defaults, config);
  // 成对的添加元素
  var requestInterceptorChain = [];
  this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
    requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
  });
  
  var responseInterceptorChain = [];
  this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
    responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
  });
  
  var chain = [dispatchRequest, undefined];
  
  Array.prototype.unshift.apply(chain, requestInterceptorChain);
  chain.concat(responseInterceptorChain);
  
  promise = Promise.resolve(config);
  while (chain.length) {
    promise = promise.then(chain.shift(), chain.shift());
  }
  return promise;
} 